unit MainTestFormU;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.ComCtrls,
  Vcl.StdCtrls, AVUtils,
  AVThread, AVAnime;

type
  TTest1Data = class(TObject)
  public
    DoWrite: boolean;
    SleepTime: integer;
    WorkQueue: TAVThreadQueue<integer>;
    WorkQueueMaxSize: integer;
  end;

  TTest1 = class(TObject)
  private
    fWorkQueueMaxSize: integer;
    fReaderSleepTime: integer;
    fWriterSleepTime: integer;
    fManagerSleepTime: integer;
    fTasksDone: integer;
    function GetTaskData(writer: boolean; SleepTime: integer): TTest1Data;
    procedure Task(Thread: TAVPoolThread);
    procedure TaskCallback(Thread: TAVPoolThread);
    procedure TaskManager(Thread: TAVPoolThread);
  public
    WorkQueue: TAVThreadQueue<integer>;

    constructor Create;
    Destructor Destroy; override;

    procedure Run;
    procedure Stop;

    property WorkQueueMaxSize: integer read fWorkQueueMaxSize
      write fWorkQueueMaxSize;
    property ReaderSleepTime: integer read fReaderSleepTime
      write fReaderSleepTime;
    property WriterSleepTime: integer read fWriterSleepTime
      write fWriterSleepTime;
    property ManagerSleepTime: integer read fManagerSleepTime
      write fManagerSleepTime;
    property TasksDone: integer read fTasksDone;
  end;

type
  TMainTestForm = class(TForm)
    Panel1: TPanel;
    eUpdateTime: TEdit;
    Timer: TTimer;
    Label2: TLabel;
    eAVThreadCount: TEdit;
    Label3: TLabel;
    eThreadInPool: TEdit;
    prMaxThread: TProgressBar;
    Label4: TLabel;
    eMaxThreadCount: TEdit;
    Label5: TLabel;
    eUsedThreadCount: TEdit;
    prUsedThread: TProgressBar;
    Label6: TLabel;
    eReadyThreadCount: TEdit;
    Label7: TLabel;
    eMinThreadCountSet: TEdit;
    eMinThreadCount: TEdit;
    Button1: TButton;
    chbUpdateInfoTime: TCheckBox;
    Label12: TLabel;
    ePoolQueueSize: TEdit;
    eMaxThreadCountSet: TEdit;
    Button6: TButton;
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    btTest1Run: TButton;
    btTest1Stop: TButton;
    Label1: TLabel;
    eWorkQueueMaxSize: TEdit;
    eWorkQueueMaxSizeSet: TEdit;
    Button2: TButton;
    prTest1Queue: TProgressBar;
    Label11: TLabel;
    eWorkQueueSize: TEdit;
    Label8: TLabel;
    eManagerSleepTime: TEdit;
    eManagerSleepTimeSet: TEdit;
    Button3: TButton;
    Label9: TLabel;
    eWriterSleepTime: TEdit;
    eWriterSleepTimeSet: TEdit;
    Button4: TButton;
    Label10: TLabel;
    eReaderSleepTime: TEdit;
    eReaderSleepTimeSet: TEdit;
    Button5: TButton;
    Label13: TLabel;
    eTasksDone: TEdit;
    TabSheet2: TTabSheet;
    Panel3: TPanel;
    Panel4: TPanel;
    Panel2: TPanel;
    Panel5: TPanel;
    Panel6: TPanel;
    Panel7: TPanel;
    procedure eUpdateTimeChange(Sender: TObject);
    procedure TimerTimer(Sender: TObject);
    procedure btTest1RunClick(Sender: TObject);
    procedure btTest1StopClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure chbUpdateInfoTimeClick(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Panel2MouseEnter(Sender: TObject);
    procedure Panel2MouseLeave(Sender: TObject);
  private
    Test1: TTest1;
    AniCon: TAVAnimeContext;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

var
  MainTestForm: TMainTestForm;

implementation

// TTest1

constructor TTest1.Create;
begin
  inherited Create;
  WorkQueue := TAVThreadQueue<integer>.Create;
  fWorkQueueMaxSize := 100;
  fReaderSleepTime := 10;
  fWriterSleepTime := 10;
  fManagerSleepTime := 10;
end;

Destructor TTest1.Destroy;
begin
  Stop;
  WorkQueue.Free;
  inherited Destroy;
end;

function TTest1.GetTaskData(writer: boolean; SleepTime: integer): TTest1Data;
begin
  Result := TTest1Data.Create;
  Result.WorkQueue := WorkQueue;
  Result.DoWrite := writer;
  Result.SleepTime := SleepTime;
  Result.WorkQueueMaxSize := fWorkQueueMaxSize;
end;

procedure TTest1.TaskCallback(Thread: TAVPoolThread);
begin
  Thread.Synchronize(Thread,
    procedure()
    begin
      Inc(fTasksDone);
      MainTestForm.eTasksDone.Text := IntToStr(fTasksDone);
    end
  )
end;

procedure TTest1.Task(Thread: TAVPoolThread);
var
  taskData: TTest1Data;
  n: integer;
begin
  taskData := TTest1Data(Thread.Job.Data);
  if taskData.DoWrite then
  begin
    if taskData.WorkQueueMaxSize > taskData.WorkQueue.Count then
      taskData.WorkQueue.Enqueue(Random(100));
  end
  else
    taskData.WorkQueue.Dequeue(n);
  Thread.Sleep(taskData.SleepTime);
end;

procedure TTest1.TaskManager(Thread: TAVPoolThread);
var
  writer: boolean;
  SleepTime: integer;
  r: integer;
begin
  while not Thread.Terminated and not Thread.Job.Cancel do
  begin
    Randomize;
    r := Random(2);
    writer := r = 0;
    if writer then
      SleepTime := fWriterSleepTime
    else
      SleepTime := fReaderSleepTime;
    AVThreadPool.AddJob(Task, GetTaskData(writer, Random(SleepTime)), 'Task1', '', TaskCallback);
    Thread.Sleep(fManagerSleepTime);
  end;
end;

procedure TTest1.Run;
begin
  Stop;
  fTasksDone := 0;
  AVThreadPool.AddJob(TaskManager, nil, 'Task1');
end;

procedure TTest1.Stop;
begin
  AVThreadPool.CancelGroup('Task1', true);
end;

{$R *.dfm}
// TMainTestForm

procedure TMainTestForm.btTest1RunClick(Sender: TObject);
begin
  Test1.Run;
end;

constructor TMainTestForm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Test1 := TTest1.Create;
  AniCon := TAVAnimeContext.Create;
end;

destructor TMainTestForm.Destroy;
begin
  Test1.Free;
  inherited Destroy;
end;

procedure TMainTestForm.eUpdateTimeChange(Sender: TObject);
var
  n: integer;
begin
  n := StrToIntAnyway(eUpdateTime.Text);
  if n < 50 then
    n := 50;
  Timer.Interval := n;
end;

procedure TMainTestForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  AniCon.Free;
end;

procedure TMainTestForm.Panel2MouseEnter(Sender: TObject);
begin
  TAVAnime(Sender).Cancel(AniCon);
  TAVAnime(Sender).mode(mDec).Speed(sMedium).Int('Height', 100).Run(AniCon);
  TAVAnime(Sender).Color('Color', clLime).Run(AniCon);
end;

procedure TMainTestForm.Panel2MouseLeave(Sender: TObject);
begin
  TAVAnime(Sender).Cancel(AniCon);
  TAVAnime(Sender).mode(mDec).Speed(sMedium).Int('Height', 40).Run(AniCon);
  TAVAnime(Sender).Color('Color', clBlue).Run(AniCon);
end;

procedure TMainTestForm.btTest1StopClick(Sender: TObject);
begin
  Test1.Stop;
end;

procedure TMainTestForm.Button1Click(Sender: TObject);
var
  n: integer;
begin
  n := StrToIntAnyway(eMinThreadCountSet.Text);
  if n < 1 then
    n := 1;
  AVThreadPool.MinThreadCount := n;
end;

procedure TMainTestForm.Button2Click(Sender: TObject);
var
  n: integer;
begin
  n := StrToIntAnyway(eWorkQueueMaxSizeSet.Text);
  if n < 1 then
    n := 1;
  Test1.WorkQueueMaxSize := n;
end;

procedure TMainTestForm.Button3Click(Sender: TObject);
var
  n: integer;
begin
  n := StrToIntAnyway(eManagerSleepTimeSet.Text);
  if n < 1 then
    n := 1;
  Test1.ManagerSleepTime := n;
end;

procedure TMainTestForm.Button4Click(Sender: TObject);
var
  n: integer;
begin
  n := StrToIntAnyway(eWriterSleepTimeSet.Text);
  if n < 1 then
    n := 1;
  Test1.WriterSleepTime := n;
end;

procedure TMainTestForm.Button5Click(Sender: TObject);
var
  n: integer;
begin
  n := StrToIntAnyway(eReaderSleepTimeSet.Text);
  if n < 1 then
    n := 1;
  Test1.ReaderSleepTime := n;
end;

procedure TMainTestForm.Button6Click(Sender: TObject);
var
  n: integer;
begin
  n := StrToIntAnyway(eMaxThreadCountSet.Text);
  if n < 10 then
    n := 10;
  AVThreadPool.MaxThreadCount := n;
end;

procedure TMainTestForm.chbUpdateInfoTimeClick(Sender: TObject);
begin
  Timer.Enabled := chbUpdateInfoTime.Checked;
end;

procedure TMainTestForm.TimerTimer(Sender: TObject);
var
  n: integer;
begin
  eAVThreadCount.Text := IntToStr(AVThread.AVThreadCount);
  eThreadInPool.Text := IntToStr(AVThreadPool.ActiveThreadCount);
  prMaxThread.Max := InRange(AVThreadPool.MaxThreadCount, 0, MaxInt);
  prMaxThread.Position := InRange(AVThreadPool.ActiveThreadCount, 0, prMaxThread.Max);
  eMaxThreadCount.Text := IntToStr(AVThreadPool.MaxThreadCount);

  n := AVThreadPool.ActiveThreadCount - AVThreadPool.ReadyThreadCount;
  eUsedThreadCount.Text := IntToStr(n);
  prUsedThread.Max := InRange(AVThreadPool.ActiveThreadCount, 0, MaxInt);
  prUsedThread.Position := InRange(n, 0, prUsedThread.Max);
  eReadyThreadCount.Text := IntToStr(AVThreadPool.ReadyThreadCount);
  eMinThreadCount.Text := IntToStr(AVThreadPool.MinThreadCount);
  ePoolQueueSize.Text := IntToStr(AVThreadPool.QueueCount);

  // Test1:
  eWorkQueueMaxSize.Text := IntToStr(Test1.WorkQueueMaxSize);
  eManagerSleepTime.Text := IntToStr(Test1.ManagerSleepTime);
  eWriterSleepTime.Text := IntToStr(Test1.WriterSleepTime);
  eReaderSleepTime.Text := IntToStr(Test1.ReaderSleepTime);
  prTest1Queue.Max := InRange(Test1.WorkQueueMaxSize, 0, MaxInt);
  prTest1Queue.Position := InRange(Test1.WorkQueue.Count, 0, prTest1Queue.Max);
  eWorkQueueSize.Text := IntToStr(Test1.WorkQueue.Count);
  //eTasksDone.Text := IntToStr(Test1.TasksDone);
end;

end.
